﻿using System;
using System.IO;
using System.Text;
using System.Web.Mvc;
using System.Collections.Generic;

namespace Web.Core.ActionFilters
{
    public class StaticAttribute : ActionFilterAttribute
    {
        private string filePath;
        private FileInfo fileInfo;
        private bool updating;
        private bool needUpdate;
        private readonly string template;
        private readonly TimeSpan expireTime;
        private readonly object updateLock = new object();
        public StaticAttribute(int second)
            : this(second, null)
        {

        }
        public StaticAttribute(int second, string template)
        {
            this.template = template;
            expireTime = new TimeSpan(0, 0, second);
        }

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var request = filterContext.HttpContext.Request;

            if (request.Headers["Cache-Control"] == "no-cache")
            {
                return;
            }
            const string baseAddress = "http://www.silenthink.com/html/";
            var routeData = filterContext.Controller.ControllerContext.RouteData;
            if (!string.IsNullOrEmpty(template))
            {
                var uriTemplate = new UriTemplate(template);
                var segmentParams = uriTemplate.PathSegmentVariableNames;
                var dic = new Dictionary<string, string>();

                foreach (var p in segmentParams)
                {
                    var v = routeData.Values[p].ToString();
                    if (!string.IsNullOrEmpty(v))
                    {
                        dic[p] = v;
                    }
                }
                var temp = uriTemplate.BindByName(new Uri(baseAddress), dic);
                filePath = temp.AbsolutePath;
            }
            filePath = filterContext.HttpContext.Server.MapPath(filePath);
            fileInfo = new FileInfo(filePath);
            needUpdate = DateTime.Now - fileInfo.LastWriteTime > expireTime;

            if (!needUpdate && fileInfo.Exists)
            {
                filterContext.Result = new FilePathResult(filePath, "text/html");
            }
        }

        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            var request = filterContext.HttpContext.Request;

            if (!needUpdate || updating || request.Headers["Cache-Control"] == "no-cache")
            {
                return;
            }
        
            lock (updateLock)
            {
                if (updating) return;
                updating = true;

                var viewResult = filterContext.Result as ViewResult;
                if (viewResult == null) return;
                string html;
                using (var writer = new StringWriter())
                {
                    var viewContext = new ViewContext(filterContext, viewResult.View, viewResult.ViewData, viewResult.TempData, writer);

                    viewResult.View.Render(viewContext, writer);

                    html = viewContext.Writer.ToString();
                }
                var bytes = Encoding.UTF8.GetBytes(html);
                using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                {
                    fileStream.Write(bytes, 0, bytes.Length);
                }
                updating = false;
            }
        }
    }
}